#!/usr/bin/env python
#
# Various units for simulation convenience
#
# Author:   Mike Murphy <mamurph@cs.clemson.edu>
# Revision: 23 September 2009
#
#   Copyright 2009 Clemson University
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
# This material is based upon work supported under a National Science
# Foundation Graduate Research Fellowship. Any opinions, findings,
# conclusions or recommendations expressed in this publication are those of
# the author(s) and do not necessarily reflect the views of the National
# Science Foundation.

'''
Various units of time, size, etc. for simulation convenience. All unit names
begin with the prefix u_, to avoid namespace collisions if all units are
imported into the working namespace.
'''


############################# Size Constants (in bytes) #####################

u_KB = 10**3
u_KiB = 2**10
u_MB = 10**6
u_MiB = 2**20
u_GB = 10**9
u_GiB = 2**30
u_TB = 10**12
u_TiB = 2**40
u_PB = 10**15
u_PiB = 2**50


############################# Speed Constants ###############################

# Network speeds are ALWAYS specified in decimal bits/bytes per sec. These
# constants are in terms of BYTES.

u_Kbps = 125
u_KBps = 1000
u_Mbps = 125000
u_MBps = 10**6
u_Gbps = 125000000
u_GBps = 10**9


############################# Time Constants ################################

# Two granularity sets: SG (seconds) and MG (minutes). Pick one per experiment,
# and BE CONSISTENT!

u_SG_SECOND = 1
u_SG_MINUTE = 60
u_SG_HOUR = 3600
u_SG_DAY = 86400
u_SG_WEEK = 604800
u_SG_FORTNIGHT = 1209600
u_SG_MONTH = 2592000           # 30 days
u_SG_QUARTER = 7862400         # 13 weeks
u_SG_YEAR = 31536000           # 365 days


# No seconds at MG
u_MG_MINUTE = 1
u_MG_HOUR = 60
u_MG_DAY = 1440
u_MG_WEEK = 10080
u_MG_FORTNIGHT = 20160
u_MG_MONTH = 43200             # 30 days
u_MG_QUARTER = 131040          # 13 weeks
u_MG_YEAR = 525600             # 365 days


# Some oddball stuff for annual environmental simulations

# Northern hemisphere
u_SG_WINTER_NORTH = 0
u_SG_SPRING_NORTH = u_SG_QUARTER
u_SG_SUMMER_NORTH = 2 * u_SG_QUARTER
u_SG_AUTUMN_NORTH = 3 * u_SG_QUARTER

u_MG_WINTER_NORTH = 0
u_MG_SPRING_NORTH = u_MG_QUARTER
u_MG_SUMMER_NORTH = 2 * u_MG_QUARTER
u_MG_AUTUMN_NORTH = 3 * u_MG_QUARTER

# Southern hemisphere
u_SG_WINTER_SOUTH = u_SG_SUMMER_NORTH
u_SG_SPRING_SOUTH = u_SG_AUTUMN_NORTH
u_SG_SUMMER_SOUTH = u_SG_WINTER_NORTH
u_SG_AUTUMN_SOUTH = u_SG_SPRING_NORTH

u_MG_WINTER_SOUTH = u_MG_SUMMER_NORTH
u_MG_SPRING_SOUTH = u_MG_AUTUMN_NORTH
u_MG_SUMMER_SOUTH = u_MG_WINTER_NORTH
u_MG_AUTUMN_SOUTH = u_MG_SPRING_NORTH


############################## Formatting Functions ##########################

# size in BYTES
def fmt_size(size):
   '''
   Produces a human-readable representation of a size in bytes. This readable
   representation will use a binary magnitude unit (B, KiB, MiB, GiB, TiB,
   or PiB). Values over 1024 pebibytes will be reported in pebibytes.

   @param size: Size to convert, in bytes
   @type size: int

   @rtype: str
   @return: a string containing the formatted quantity with a unit name
   '''
   names = [ ('B', 1), ('KiB', u_KiB), ('MiB', u_MiB), ('GiB', u_GiB), \
             ('TiB', u_TiB), ('PiB', u_PiB) ]
   szf = float(size)
   value = 0
   chosen = 'B'
   for name, fact in names:
      x = szf / float(fact)
      if x < 1:
         break
      chosen = name
      value = x
   return '%0.2f %s' % (value, chosen)
#

# speed in BYTES per second
def fmt_speed(speed):
   '''
   Produces a human-readable speed indication in *bits* per second, with
   decimal magnitude units (bps, Kbps, Mbps, or Gbps), from a speed input in
   *BYTES* per second. Values over 1000 Gbps will be reported in Gbps.

   @param speed: Speed in BYTES per second

   @rtype: str
   @return: a string containing the formatted quantity with a unit name
   '''
   names = [('bps', 0.125), ('Kbps', u_Kbps), ('Mbps', u_Mbps), \
            ('Gbps', u_Gbps)]
   spf = float(speed)
   value = 0
   chosen = 'less than 1 bps'
   if speed == 0:
      return '<speed unused>'
   for name, fact in names:
      x = spf / float(fact)
      if x < 1:
         break
      chosen = name
      value = x
   return '%0.2f %s' % (value, chosen)
#
